;solution for euler 54
(defparameter *card-values* "23456789TJQKA")
(defparameter *card-suits* "HCSD")

;note: almost done
;need to remove unused cards from hands
;need to read in data from file


(defun consecutive? (hand)
	(dotimes (i (- (length hand) 1))
		(when (/= 1 (- (elt hand (+ i 1)) (elt hand i))) 
			(return-from consecutive? nil)))
	(return-from consecutive? t))

(defun max-count (hand)
	(let ((maxc 0))
		(dotimes (i (length hand))
			(when (> (count (elt hand i) hand) maxc)
				(setf maxc (count (elt hand i) hand))))
	(return-from max-count maxc)))

(defun set-of-values (hand)
	(return-from set-of-values
		(map 'vector #'(lambda (a) (mod a 13)) hand)))
	
(defun num-with-count (count hand)
	(let ((num 0) (values (remove-duplicates hand)))
		(dotimes (i (length values))
			(when (= (count (elt values i) hand) count)
				(incf num)))
	(return-from num-with-count num)))
	
(defun straight? (hand)
	(if (consecutive? (set-of-values hand))
		(return-from straight? hand) 
		(return-from straight? nil)))

	
(defun gay? (name)
	(when (string= name "eric") (return-from gay? t))
	(return-from gay? "unknown"))


(defun straight-flush? (hand)
	(if (consecutive? hand)
		(return-from straight-flush? hand) 
		(return-from straight-flush? nil)))

(defun royal-flush? (hand)
	(if (and 
			(consecutive? hand)
			(= (mod (elt hand 0) 13) 8))
		(return-from royal-flush? hand)
		(return-from royal-flush? nil)))

(defun flush? (hand)
	(if (= (max-count (map 'vector #'(lambda (a) (floor (/ a 13))) hand))
			5)
		(return-from flush? hand)
		(return-from flush? nil)))

(defun four-of-a-kind? (hand)
	(when (= (max-count (set-of-values hand)) 4)
		(setf hand (remove-if #'(lambda (a) (= (count a hand) 1)) hand))
		(return-from four-of-a-kind? hand))
	(return-from four-of-a-kind? nil))
	
(defun three-of-a-kind? (hand)
	(setf hand (set-of-values hand))
	(when (= (max-count (set-of-values hand)) 3)
		(setf hand (remove-if #'(lambda (a) (= (count a hand) 1)) hand))
		(return-from three-of-a-kind? hand))
		(return-from three-of-a-kind? nil))

(defun one-pair? (hand)
	(when (= (max-count (set-of-values hand) 2)
		(setf hand (remove-if #'(lambda (a) (= (count a hand) 1)) hand))
		(return-from one-pair? hand))
	(return-from one-pair? nil))
		
(defun two-pairs? (hand)
	(when (= (num-with-count 2 (set-of-values hand)))
			(setf hand (remove-if #'(lambda (a) (= (count a hand) 1)) hand))
			(return-from two-pairs? hand))
	(return-from two-pairs? nil))

(defun full-house? (hand)
	(when (and
			(= (num-with-count 2 (set-of-values hand)) 1)
			(= (num-with-count 3 (set-of-values hand)) 1))
		(return-from full-house? hand))
	(return-from full-house? nil))
			


(defparameter *hands* 
	(list #'royal-flush? #'straight-flush? #'four-of-a-kind? #'full-house?
		#'flush? #'straight? #'three-of-a-kind? #'two-pairs? #'one-pair?))
	
(defun score-hand (hand)
	(sort hand #'<)
	(let ((score 0) resulthand)
		(dolist (test *hands*)
			(setf resulthand (funcall test hand))
			(when (/= nil resulthand) (return))
			(incf score))
		(return-from score-hand score)))
	

(defun parse-hand (input)
	(let ((pos 0) (rcard)
			(hand (vector)) (curval 0))
		(setf input (string-trim " " input))
		(loop
			(when (> (+ pos 2) (length input)) (return))
			(setf rcard (subseq input pos (+ pos 2)))
			(setf curval (position (char rcard 0) *card-values*))
			(incf curval (* (position (char rcard 1) *card-suits*) 13))
			(setf hand (concatenate 'vector (vector curval) hand))
			(incf pos 3))
		(return-from parse-hand hand)))
			
(defun player1-win (bothhands)
	(let (
		(hand1 (parse-hand (subseq bothhands 0 (floor (/ (length bothhands) 2)))))
		(hand2 (parse-hand (subseq bothhands (floor (/ (length bothhands) 2)))))
		score1 score2)
		(print hand1)
		(print hand2)
		(setf score1 (score-hand hand1))
		(setf score2 (score-hand hand2))
		(when (< score1 score2) (return-from player1-win t))
		(return-from player1-win (break-tie hand1 hand2))))
	
(defun break-tie (hand1 hand2)
	(setf hand1 (set-of-values hand1))
	(setf hand2 (set-of-values hand2))
	(sort hand1 #'>)
	(sort hand2 #'>)
	(let ((dif (mismatch hand1 hand2)))
		(return-from break-tie (> (elt hand1 dif) (elt hand2 dif)))))

(defun solve-euler54 ()
	(let ((wins1 0))
		
		(format t "Euler 54:~a" wins1)))